{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "<a href=\"https://www.bigdatauniversity.com\"><img src=\"https://ibm.box.com/shared/static/cw2c7r3o20w9zn8gkecaeyjhgw3xdgbj.png\" width=\"400\" align=\"center\"></a>\n",
    "\n",
    "<h1><center>Decision Trees</center></h1>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "In this lab exercise, you will learn a popular machine learning algorithm, Decision Tree. You will use this classification algorithm to build a model from historical data of patients, and their response to different medications. Then you use the trained decision tree to predict the class of a unknown patient, or to find a proper drug for a new patient."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h1>Table of contents</h1>\n",
    "\n",
    "<div class=\"alert alert-block alert-info\" style=\"margin-top: 20px\">\n",
    "    <ol>\n",
    "        <li><a href=\"#about_dataset\">About the dataset</a></li>\n",
    "        <li><a href=\"#downloading_data\">Downloading the Data</a></li>\n",
    "        <li><a href=\"#pre-processing\">Pre-processing</a></li>\n",
    "        <li><a href=\"#setting_up_tree\">Setting up the Decision Tree</a></li>\n",
    "        <li><a href=\"#modeling\">Modeling</a></li>\n",
    "        <li><a href=\"#prediction\">Prediction</a></li>\n",
    "        <li><a href=\"#evaluation\">Evaluation</a></li>\n",
    "        <li><a href=\"#visualization\">Visualization</a></li>\n",
    "    </ol>\n",
    "</div>\n",
    "<br>\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "Import the Following Libraries:\n",
    "<ul>\n",
    "    <li> <b>numpy (as np)</b> </li>\n",
    "    <li> <b>pandas</b> </li>\n",
    "    <li> <b>DecisionTreeClassifier</b> from <b>sklearn.tree</b> </li>\n",
    "</ul>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "outputs": [],
   "source": [
    "import numpy as np \n",
    "import pandas as pd\n",
    "from sklearn.tree import DecisionTreeClassifier"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\u001b[0;31mInit signature:\u001b[0m\n",
       "\u001b[0mDecisionTreeClassifier\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\u001b[0m\n",
       "\u001b[0;34m\u001b[0m    \u001b[0mcriterion\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'gini'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
       "\u001b[0;34m\u001b[0m    \u001b[0msplitter\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'best'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
       "\u001b[0;34m\u001b[0m    \u001b[0mmax_depth\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
       "\u001b[0;34m\u001b[0m    \u001b[0mmin_samples_split\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
       "\u001b[0;34m\u001b[0m    \u001b[0mmin_samples_leaf\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
       "\u001b[0;34m\u001b[0m    \u001b[0mmin_weight_fraction_leaf\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
       "\u001b[0;34m\u001b[0m    \u001b[0mmax_features\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
       "\u001b[0;34m\u001b[0m    \u001b[0mrandom_state\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
       "\u001b[0;34m\u001b[0m    \u001b[0mmax_leaf_nodes\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
       "\u001b[0;34m\u001b[0m    \u001b[0mmin_impurity_decrease\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
       "\u001b[0;34m\u001b[0m    \u001b[0mmin_impurity_split\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
       "\u001b[0;34m\u001b[0m    \u001b[0mclass_weight\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
       "\u001b[0;34m\u001b[0m    \u001b[0mpresort\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
       "\u001b[0;34m\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
       "\u001b[0;31mDocstring:\u001b[0m     \n",
       "A decision tree classifier.\n",
       "\n",
       "Read more in the :ref:`User Guide <tree>`.\n",
       "\n",
       "Parameters\n",
       "----------\n",
       "criterion : string, optional (default=\"gini\")\n",
       "    The function to measure the quality of a split. Supported criteria are\n",
       "    \"gini\" for the Gini impurity and \"entropy\" for the information gain.\n",
       "\n",
       "splitter : string, optional (default=\"best\")\n",
       "    The strategy used to choose the split at each node. Supported\n",
       "    strategies are \"best\" to choose the best split and \"random\" to choose\n",
       "    the best random split.\n",
       "\n",
       "max_depth : int or None, optional (default=None)\n",
       "    The maximum depth of the tree. If None, then nodes are expanded until\n",
       "    all leaves are pure or until all leaves contain less than\n",
       "    min_samples_split samples.\n",
       "\n",
       "min_samples_split : int, float, optional (default=2)\n",
       "    The minimum number of samples required to split an internal node:\n",
       "\n",
       "    - If int, then consider `min_samples_split` as the minimum number.\n",
       "    - If float, then `min_samples_split` is a fraction and\n",
       "      `ceil(min_samples_split * n_samples)` are the minimum\n",
       "      number of samples for each split.\n",
       "\n",
       "    .. versionchanged:: 0.18\n",
       "       Added float values for fractions.\n",
       "\n",
       "min_samples_leaf : int, float, optional (default=1)\n",
       "    The minimum number of samples required to be at a leaf node.\n",
       "    A split point at any depth will only be considered if it leaves at\n",
       "    least ``min_samples_leaf`` training samples in each of the left and\n",
       "    right branches.  This may have the effect of smoothing the model,\n",
       "    especially in regression.\n",
       "\n",
       "    - If int, then consider `min_samples_leaf` as the minimum number.\n",
       "    - If float, then `min_samples_leaf` is a fraction and\n",
       "      `ceil(min_samples_leaf * n_samples)` are the minimum\n",
       "      number of samples for each node.\n",
       "\n",
       "    .. versionchanged:: 0.18\n",
       "       Added float values for fractions.\n",
       "\n",
       "min_weight_fraction_leaf : float, optional (default=0.)\n",
       "    The minimum weighted fraction of the sum total of weights (of all\n",
       "    the input samples) required to be at a leaf node. Samples have\n",
       "    equal weight when sample_weight is not provided.\n",
       "\n",
       "max_features : int, float, string or None, optional (default=None)\n",
       "    The number of features to consider when looking for the best split:\n",
       "\n",
       "        - If int, then consider `max_features` features at each split.\n",
       "        - If float, then `max_features` is a fraction and\n",
       "          `int(max_features * n_features)` features are considered at each\n",
       "          split.\n",
       "        - If \"auto\", then `max_features=sqrt(n_features)`.\n",
       "        - If \"sqrt\", then `max_features=sqrt(n_features)`.\n",
       "        - If \"log2\", then `max_features=log2(n_features)`.\n",
       "        - If None, then `max_features=n_features`.\n",
       "\n",
       "    Note: the search for a split does not stop until at least one\n",
       "    valid partition of the node samples is found, even if it requires to\n",
       "    effectively inspect more than ``max_features`` features.\n",
       "\n",
       "random_state : int, RandomState instance or None, optional (default=None)\n",
       "    If int, random_state is the seed used by the random number generator;\n",
       "    If RandomState instance, random_state is the random number generator;\n",
       "    If None, the random number generator is the RandomState instance used\n",
       "    by `np.random`.\n",
       "\n",
       "max_leaf_nodes : int or None, optional (default=None)\n",
       "    Grow a tree with ``max_leaf_nodes`` in best-first fashion.\n",
       "    Best nodes are defined as relative reduction in impurity.\n",
       "    If None then unlimited number of leaf nodes.\n",
       "\n",
       "min_impurity_decrease : float, optional (default=0.)\n",
       "    A node will be split if this split induces a decrease of the impurity\n",
       "    greater than or equal to this value.\n",
       "\n",
       "    The weighted impurity decrease equation is the following::\n",
       "\n",
       "        N_t / N * (impurity - N_t_R / N_t * right_impurity\n",
       "                            - N_t_L / N_t * left_impurity)\n",
       "\n",
       "    where ``N`` is the total number of samples, ``N_t`` is the number of\n",
       "    samples at the current node, ``N_t_L`` is the number of samples in the\n",
       "    left child, and ``N_t_R`` is the number of samples in the right child.\n",
       "\n",
       "    ``N``, ``N_t``, ``N_t_R`` and ``N_t_L`` all refer to the weighted sum,\n",
       "    if ``sample_weight`` is passed.\n",
       "\n",
       "    .. versionadded:: 0.19\n",
       "\n",
       "min_impurity_split : float, (default=1e-7)\n",
       "    Threshold for early stopping in tree growth. A node will split\n",
       "    if its impurity is above the threshold, otherwise it is a leaf.\n",
       "\n",
       "    .. deprecated:: 0.19\n",
       "       ``min_impurity_split`` has been deprecated in favor of\n",
       "       ``min_impurity_decrease`` in 0.19. The default value of\n",
       "       ``min_impurity_split`` will change from 1e-7 to 0 in 0.23 and it\n",
       "       will be removed in 0.25. Use ``min_impurity_decrease`` instead.\n",
       "\n",
       "class_weight : dict, list of dicts, \"balanced\" or None, default=None\n",
       "    Weights associated with classes in the form ``{class_label: weight}``.\n",
       "    If not given, all classes are supposed to have weight one. For\n",
       "    multi-output problems, a list of dicts can be provided in the same\n",
       "    order as the columns of y.\n",
       "\n",
       "    Note that for multioutput (including multilabel) weights should be\n",
       "    defined for each class of every column in its own dict. For example,\n",
       "    for four-class multilabel classification weights should be\n",
       "    [{0: 1, 1: 1}, {0: 1, 1: 5}, {0: 1, 1: 1}, {0: 1, 1: 1}] instead of\n",
       "    [{1:1}, {2:5}, {3:1}, {4:1}].\n",
       "\n",
       "    The \"balanced\" mode uses the values of y to automatically adjust\n",
       "    weights inversely proportional to class frequencies in the input data\n",
       "    as ``n_samples / (n_classes * np.bincount(y))``\n",
       "\n",
       "    For multi-output, the weights of each column of y will be multiplied.\n",
       "\n",
       "    Note that these weights will be multiplied with sample_weight (passed\n",
       "    through the fit method) if sample_weight is specified.\n",
       "\n",
       "presort : bool, optional (default=False)\n",
       "    Whether to presort the data to speed up the finding of best splits in\n",
       "    fitting. For the default settings of a decision tree on large\n",
       "    datasets, setting this to true may slow down the training process.\n",
       "    When using either a smaller dataset or a restricted depth, this may\n",
       "    speed up the training.\n",
       "\n",
       "Attributes\n",
       "----------\n",
       "classes_ : array of shape = [n_classes] or a list of such arrays\n",
       "    The classes labels (single output problem),\n",
       "    or a list of arrays of class labels (multi-output problem).\n",
       "\n",
       "feature_importances_ : array of shape = [n_features]\n",
       "    The feature importances. The higher, the more important the\n",
       "    feature. The importance of a feature is computed as the (normalized)\n",
       "    total reduction of the criterion brought by that feature.  It is also\n",
       "    known as the Gini importance [4]_.\n",
       "\n",
       "max_features_ : int,\n",
       "    The inferred value of max_features.\n",
       "\n",
       "n_classes_ : int or list\n",
       "    The number of classes (for single output problems),\n",
       "    or a list containing the number of classes for each\n",
       "    output (for multi-output problems).\n",
       "\n",
       "n_features_ : int\n",
       "    The number of features when ``fit`` is performed.\n",
       "\n",
       "n_outputs_ : int\n",
       "    The number of outputs when ``fit`` is performed.\n",
       "\n",
       "tree_ : Tree object\n",
       "    The underlying Tree object. Please refer to\n",
       "    ``help(sklearn.tree._tree.Tree)`` for attributes of Tree object and\n",
       "    :ref:`sphx_glr_auto_examples_tree_plot_unveil_tree_structure.py`\n",
       "    for basic usage of these attributes.\n",
       "\n",
       "Notes\n",
       "-----\n",
       "The default values for the parameters controlling the size of the trees\n",
       "(e.g. ``max_depth``, ``min_samples_leaf``, etc.) lead to fully grown and\n",
       "unpruned trees which can potentially be very large on some data sets. To\n",
       "reduce memory consumption, the complexity and size of the trees should be\n",
       "controlled by setting those parameter values.\n",
       "\n",
       "The features are always randomly permuted at each split. Therefore,\n",
       "the best found split may vary, even with the same training data and\n",
       "``max_features=n_features``, if the improvement of the criterion is\n",
       "identical for several splits enumerated during the search of the best\n",
       "split. To obtain a deterministic behaviour during fitting,\n",
       "``random_state`` has to be fixed.\n",
       "\n",
       "See also\n",
       "--------\n",
       "DecisionTreeRegressor\n",
       "\n",
       "References\n",
       "----------\n",
       "\n",
       ".. [1] https://en.wikipedia.org/wiki/Decision_tree_learning\n",
       "\n",
       ".. [2] L. Breiman, J. Friedman, R. Olshen, and C. Stone, \"Classification\n",
       "       and Regression Trees\", Wadsworth, Belmont, CA, 1984.\n",
       "\n",
       ".. [3] T. Hastie, R. Tibshirani and J. Friedman. \"Elements of Statistical\n",
       "       Learning\", Springer, 2009.\n",
       "\n",
       ".. [4] L. Breiman, and A. Cutler, \"Random Forests\",\n",
       "       https://www.stat.berkeley.edu/~breiman/RandomForests/cc_home.htm\n",
       "\n",
       "Examples\n",
       "--------\n",
       ">>> from sklearn.datasets import load_iris\n",
       ">>> from sklearn.model_selection import cross_val_score\n",
       ">>> from sklearn.tree import DecisionTreeClassifier\n",
       ">>> clf = DecisionTreeClassifier(random_state=0)\n",
       ">>> iris = load_iris()\n",
       ">>> cross_val_score(clf, iris.data, iris.target, cv=10)\n",
       "...                             # doctest: +SKIP\n",
       "...\n",
       "array([ 1.     ,  0.93...,  0.86...,  0.93...,  0.93...,\n",
       "        0.93...,  0.93...,  1.     ,  0.93...,  1.      ])\n",
       "\u001b[0;31mFile:\u001b[0m           ~/conda/envs/python/lib/python3.6/site-packages/sklearn/tree/tree.py\n",
       "\u001b[0;31mType:\u001b[0m           ABCMeta\n",
       "\u001b[0;31mSubclasses:\u001b[0m     ExtraTreeClassifier\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "DecisionTreeClassifier?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "<div id=\"about_dataset\">\n",
    "    <h2>About the dataset</h2>\n",
    "    Imagine that you are a medical researcher compiling data for a study. You have collected data about a set of patients, all of whom suffered from the same illness. During their course of treatment, each patient responded to one of 5 medications, Drug A, Drug B, Drug c, Drug x and y. \n",
    "    <br>\n",
    "    <br>\n",
    "    Part of your job is to build a model to find out which drug might be appropriate for a future patient with the same illness. The feature sets of this dataset are Age, Sex, Blood Pressure, and Cholesterol of patients, and the target is the drug that each patient responded to.\n",
    "    <br>\n",
    "    <br>\n",
    "    It is a sample of binary classifier, and you can use the training part of the dataset \n",
    "    to build a decision tree, and then use it to predict the class of a unknown patient, or to prescribe it to a new patient.\n",
    "</div>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "<div id=\"downloading_data\"> \n",
    "    <h2>Downloading the Data</h2>\n",
    "    To download the data, we will use !wget to download it from IBM Object Storage.\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--2019-10-04 12:05:41--  https://s3-api.us-geo.objectstorage.softlayer.net/cf-courses-data/CognitiveClass/ML0101ENv3/labs/drug200.csv\n",
      "Resolving s3-api.us-geo.objectstorage.softlayer.net (s3-api.us-geo.objectstorage.softlayer.net)... 67.228.254.193\n",
      "Connecting to s3-api.us-geo.objectstorage.softlayer.net (s3-api.us-geo.objectstorage.softlayer.net)|67.228.254.193|:443... connected.\n",
      "HTTP request sent, awaiting response... 200 OK\n",
      "Length: 6027 (5.9K) [text/csv]\n",
      "Saving to: ‘drug200.csv’\n",
      "\n",
      "drug200.csv         100%[===================>]   5.89K  --.-KB/s    in 0s      \n",
      "\n",
      "2019-10-04 12:05:41 (181 MB/s) - ‘drug200.csv’ saved [6027/6027]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "!wget -O drug200.csv https://s3-api.us-geo.objectstorage.softlayer.net/cf-courses-data/CognitiveClass/ML0101ENv3/labs/drug200.csv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__Did you know?__ When it comes to Machine Learning, you will likely be working with large datasets. As a business, where can you host your data? IBM is offering a unique opportunity for businesses, with 10 Tb of IBM Cloud Object Storage: [Sign up now for free](http://cocl.us/ML0101EN-IBM-Offer-CC)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "now, read data using pandas dataframe:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Age</th>\n",
       "      <th>Sex</th>\n",
       "      <th>BP</th>\n",
       "      <th>Cholesterol</th>\n",
       "      <th>Na_to_K</th>\n",
       "      <th>Drug</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>23</td>\n",
       "      <td>F</td>\n",
       "      <td>HIGH</td>\n",
       "      <td>HIGH</td>\n",
       "      <td>25.355</td>\n",
       "      <td>drugY</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>47</td>\n",
       "      <td>M</td>\n",
       "      <td>LOW</td>\n",
       "      <td>HIGH</td>\n",
       "      <td>13.093</td>\n",
       "      <td>drugC</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2</td>\n",
       "      <td>47</td>\n",
       "      <td>M</td>\n",
       "      <td>LOW</td>\n",
       "      <td>HIGH</td>\n",
       "      <td>10.114</td>\n",
       "      <td>drugC</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>3</td>\n",
       "      <td>28</td>\n",
       "      <td>F</td>\n",
       "      <td>NORMAL</td>\n",
       "      <td>HIGH</td>\n",
       "      <td>7.798</td>\n",
       "      <td>drugX</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>4</td>\n",
       "      <td>61</td>\n",
       "      <td>F</td>\n",
       "      <td>LOW</td>\n",
       "      <td>HIGH</td>\n",
       "      <td>18.043</td>\n",
       "      <td>drugY</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   Age Sex      BP Cholesterol  Na_to_K   Drug\n",
       "0   23   F    HIGH        HIGH   25.355  drugY\n",
       "1   47   M     LOW        HIGH   13.093  drugC\n",
       "2   47   M     LOW        HIGH   10.114  drugC\n",
       "3   28   F  NORMAL        HIGH    7.798  drugX\n",
       "4   61   F     LOW        HIGH   18.043  drugY"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_data = pd.read_csv(\"drug200.csv\", delimiter=\",\")\n",
    "my_data[0:5]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "<div id=\"practice\"> \n",
    "    <h3>Practice</h3> \n",
    "    What is the size of data? \n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(200, 6)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# write your code here\n",
    "my_data.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div href=\"pre-processing\">\n",
    "    <h2>Pre-processing</h2>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "Using <b>my_data</b> as the Drug.csv data read by pandas, declare the following variables: <br>\n",
    "\n",
    "<ul>\n",
    "    <li> <b> X </b> as the <b> Feature Matrix </b> (data of my_data) </li>\n",
    "    <li> <b> y </b> as the <b> response vector (target) </b> </li>\n",
    "</ul>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "Remove the column containing the target name since it doesn't contain numeric values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[23, 'F', 'HIGH', 'HIGH', 25.355],\n",
       "       [47, 'M', 'LOW', 'HIGH', 13.093],\n",
       "       [47, 'M', 'LOW', 'HIGH', 10.113999999999999],\n",
       "       [28, 'F', 'NORMAL', 'HIGH', 7.797999999999999],\n",
       "       [61, 'F', 'LOW', 'HIGH', 18.043]], dtype=object)"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X = my_data[['Age', 'Sex', 'BP', 'Cholesterol', 'Na_to_K']].values\n",
    "X[0:5]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As you may figure out, some features in this dataset are categorical such as __Sex__ or __BP__. Unfortunately, Sklearn Decision Trees do not handle categorical variables. But still we can convert these features to numerical values. __pandas.get_dummies()__\n",
    "Convert categorical variable into dummy/indicator variables."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[23, 0, 0, 0, 25.355],\n",
       "       [47, 1, 1, 0, 13.093],\n",
       "       [47, 1, 1, 0, 10.113999999999999],\n",
       "       [28, 0, 2, 0, 7.797999999999999],\n",
       "       [61, 0, 1, 0, 18.043]], dtype=object)"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn import preprocessing\n",
    "le_sex = preprocessing.LabelEncoder()\n",
    "le_sex.fit(['F','M'])\n",
    "X[:,1] = le_sex.transform(X[:,1]) \n",
    "\n",
    "\n",
    "le_BP = preprocessing.LabelEncoder()\n",
    "le_BP.fit([ 'LOW', 'NORMAL', 'HIGH'])\n",
    "X[:,2] = le_BP.transform(X[:,2])\n",
    "\n",
    "\n",
    "le_Chol = preprocessing.LabelEncoder()\n",
    "le_Chol.fit([ 'NORMAL', 'HIGH'])\n",
    "X[:,3] = le_Chol.transform(X[:,3]) \n",
    "\n",
    "X[0:5]\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can fill the target variable."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0    drugY\n",
       "1    drugC\n",
       "2    drugC\n",
       "3    drugX\n",
       "4    drugY\n",
       "Name: Drug, dtype: object"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y = my_data[\"Drug\"]\n",
    "y[0:5]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "<hr>\n",
    "\n",
    "<div id=\"setting_up_tree\">\n",
    "    <h2>Setting up the Decision Tree</h2>\n",
    "    We will be using <b>train/test split</b> on our <b>decision tree</b>. Let's import <b>train_test_split</b> from <b>sklearn.cross_validation</b>.\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "outputs": [],
   "source": [
    "from sklearn.model_selection import train_test_split"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "Now <b> train_test_split </b> will return 4 different parameters. We will name them:<br>\n",
    "X_trainset, X_testset, y_trainset, y_testset <br> <br>\n",
    "The <b> train_test_split </b> will need the parameters: <br>\n",
    "X, y, test_size=0.3, and random_state=3. <br> <br>\n",
    "The <b>X</b> and <b>y</b> are the arrays required before the split, the <b>test_size</b> represents the ratio of the testing dataset, and the <b>random_state</b> ensures that we obtain the same splits."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "outputs": [],
   "source": [
    "X_trainset, X_testset, y_trainset, y_testset = train_test_split(X, y, test_size=0.3, random_state=3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "<h3>Practice</h3>\n",
    "Print the shape of X_trainset and y_trainset. Ensure that the dimensions match"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(140, 5)"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# your code\n",
    "X_trainset.shape\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(140,)"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_trainset.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "Print the shape of X_testset and y_testset. Ensure that the dimensions match"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(60, 5)"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# your code\n",
    "X_testset.shape\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(60,)"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_testset.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "<hr>\n",
    "\n",
    "<div id=\"modeling\">\n",
    "    <h2>Modeling</h2>\n",
    "    We will first create an instance of the <b>DecisionTreeClassifier</b> called <b>drugTree</b>.<br>\n",
    "    Inside of the classifier, specify <i> criterion=\"entropy\" </i> so we can see the information gain of each node.\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DecisionTreeClassifier(class_weight=None, criterion='entropy', max_depth=4,\n",
       "            max_features=None, max_leaf_nodes=None,\n",
       "            min_impurity_decrease=0.0, min_impurity_split=None,\n",
       "            min_samples_leaf=1, min_samples_split=2,\n",
       "            min_weight_fraction_leaf=0.0, presort=False, random_state=None,\n",
       "            splitter='best')"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "drugTree = DecisionTreeClassifier(criterion=\"entropy\", max_depth = 4)\n",
    "drugTree # it shows the default parameters"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "Next, we will fit the data with the training feature matrix <b> X_trainset </b> and training  response vector <b> y_trainset </b>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DecisionTreeClassifier(class_weight=None, criterion='entropy', max_depth=4,\n",
       "            max_features=None, max_leaf_nodes=None,\n",
       "            min_impurity_decrease=0.0, min_impurity_split=None,\n",
       "            min_samples_leaf=1, min_samples_split=2,\n",
       "            min_weight_fraction_leaf=0.0, presort=False, random_state=None,\n",
       "            splitter='best')"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "drugTree.fit(X_trainset,y_trainset)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "<hr>\n",
    "\n",
    "<div id=\"prediction\">\n",
    "    <h2>Prediction</h2>\n",
    "    Let's make some <b>predictions</b> on the testing dataset and store it into a variable called <b>predTree</b>.\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "outputs": [],
   "source": [
    "predTree = drugTree.predict(X_testset)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "You can print out <b>predTree</b> and <b>y_testset</b> if you want to visually compare the prediction to the actual values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['drugY' 'drugX' 'drugX' 'drugX' 'drugX']\n",
      "40     drugY\n",
      "51     drugX\n",
      "139    drugX\n",
      "197    drugX\n",
      "170    drugX\n",
      "Name: Drug, dtype: object\n"
     ]
    }
   ],
   "source": [
    "print (predTree [0:5])\n",
    "print (y_testset [0:5])\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "<hr>\n",
    "\n",
    "<div id=\"evaluation\">\n",
    "    <h2>Evaluation</h2>\n",
    "    Next, let's import <b>metrics</b> from sklearn and check the accuracy of our model.\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "DecisionTrees's Accuracy:  0.9833333333333333\n"
     ]
    }
   ],
   "source": [
    "from sklearn import metrics\n",
    "import matplotlib.pyplot as plt\n",
    "print(\"DecisionTrees's Accuracy: \", metrics.accuracy_score(y_testset, predTree))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\u001b[0;31mType:\u001b[0m        module\n",
       "\u001b[0;31mString form:\u001b[0m <module 'sklearn.metrics' from '/home/jupyterlab/conda/envs/python/lib/python3.6/site-packages/sklearn/metrics/__init__.py'>\n",
       "\u001b[0;31mFile:\u001b[0m        ~/conda/envs/python/lib/python3.6/site-packages/sklearn/metrics/__init__.py\n",
       "\u001b[0;31mDocstring:\u001b[0m  \n",
       "The :mod:`sklearn.metrics` module includes score functions, performance metrics\n",
       "and pairwise metrics and distance computations.\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "metrics?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\u001b[0;31mSignature:\u001b[0m \u001b[0mmetrics\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maccuracy_score\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my_true\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my_pred\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnormalize\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msample_weight\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
       "\u001b[0;31mDocstring:\u001b[0m\n",
       "Accuracy classification score.\n",
       "\n",
       "In multilabel classification, this function computes subset accuracy:\n",
       "the set of labels predicted for a sample must *exactly* match the\n",
       "corresponding set of labels in y_true.\n",
       "\n",
       "Read more in the :ref:`User Guide <accuracy_score>`.\n",
       "\n",
       "Parameters\n",
       "----------\n",
       "y_true : 1d array-like, or label indicator array / sparse matrix\n",
       "    Ground truth (correct) labels.\n",
       "\n",
       "y_pred : 1d array-like, or label indicator array / sparse matrix\n",
       "    Predicted labels, as returned by a classifier.\n",
       "\n",
       "normalize : bool, optional (default=True)\n",
       "    If ``False``, return the number of correctly classified samples.\n",
       "    Otherwise, return the fraction of correctly classified samples.\n",
       "\n",
       "sample_weight : array-like of shape = [n_samples], optional\n",
       "    Sample weights.\n",
       "\n",
       "Returns\n",
       "-------\n",
       "score : float\n",
       "    If ``normalize == True``, return the fraction of correctly\n",
       "    classified samples (float), else returns the number of correctly\n",
       "    classified samples (int).\n",
       "\n",
       "    The best performance is 1 with ``normalize == True`` and the number\n",
       "    of samples with ``normalize == False``.\n",
       "\n",
       "See also\n",
       "--------\n",
       "jaccard_similarity_score, hamming_loss, zero_one_loss\n",
       "\n",
       "Notes\n",
       "-----\n",
       "In binary and multiclass classification, this function is equal\n",
       "to the ``jaccard_similarity_score`` function.\n",
       "\n",
       "Examples\n",
       "--------\n",
       ">>> import numpy as np\n",
       ">>> from sklearn.metrics import accuracy_score\n",
       ">>> y_pred = [0, 2, 1, 3]\n",
       ">>> y_true = [0, 1, 2, 3]\n",
       ">>> accuracy_score(y_true, y_pred)\n",
       "0.5\n",
       ">>> accuracy_score(y_true, y_pred, normalize=False)\n",
       "2\n",
       "\n",
       "In the multilabel case with binary label indicators:\n",
       "\n",
       ">>> accuracy_score(np.array([[0, 1], [1, 1]]), np.ones((2, 2)))\n",
       "0.5\n",
       "\u001b[0;31mFile:\u001b[0m      ~/conda/envs/python/lib/python3.6/site-packages/sklearn/metrics/classification.py\n",
       "\u001b[0;31mType:\u001b[0m      function\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "metrics.accuracy_score?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "__Accuracy classification score__ computes subset accuracy: the set of labels predicted for a sample must exactly match the corresponding set of labels in y_true.  \n",
    "\n",
    "In multilabel classification, the function returns the subset accuracy. If the entire set of predicted labels for a sample strictly match with the true set of labels, then the subset accuracy is 1.0; otherwise it is 0.0.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "## Practice \n",
    "Can you calculate the accuracy score without sklearn ?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "button": false,
    "collapsed": true,
    "deletable": true,
    "jupyter": {
     "outputs_hidden": true
    },
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "outputs": [],
   "source": [
    "# your code here\n",
    "No!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<hr>\n",
    "\n",
    "<div id=\"visualization\">\n",
    "    <h2>Visualization</h2>\n",
    "    Lets visualize the tree\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Notice: You might need to uncomment and install the pydotplus and graphviz libraries if you have not installed these before\n",
    "# !conda install -c conda-forge pydotplus -y\n",
    "# !conda install -c conda-forge python-graphviz -y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "button": false,
    "collapsed": true,
    "deletable": true,
    "jupyter": {
     "outputs_hidden": true
    },
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "outputs": [],
   "source": [
    "from sklearn.externals.six import StringIO\n",
    "import pydotplus\n",
    "import matplotlib.image as mpimg\n",
    "from sklearn import tree\n",
    "%matplotlib inline "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "button": false,
    "collapsed": true,
    "deletable": true,
    "jupyter": {
     "outputs_hidden": true
    },
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "outputs": [],
   "source": [
    "dot_data = StringIO()\n",
    "filename = \"drugtree.png\"\n",
    "featureNames = my_data.columns[0:5]\n",
    "targetNames = my_data[\"Drug\"].unique().tolist()\n",
    "out=tree.export_graphviz(drugTree,feature_names=featureNames, out_file=dot_data, class_names= np.unique(y_trainset), filled=True,  special_characters=True,rotate=False)  \n",
    "graph = pydotplus.graph_from_dot_data(dot_data.getvalue())  \n",
    "graph.write_png(filename)\n",
    "img = mpimg.imread(filename)\n",
    "plt.figure(figsize=(100, 200))\n",
    "plt.imshow(img,interpolation='nearest')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "button": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "source": [
    "<h2>Want to learn more?</h2>\n",
    "\n",
    "IBM SPSS Modeler is a comprehensive analytics platform that has many machine learning algorithms. It has been designed to bring predictive intelligence to decisions made by individuals, by groups, by systems – by your enterprise as a whole. A free trial is available through this course, available here: <a href=\"http://cocl.us/ML0101EN-SPSSModeler\">SPSS Modeler</a>\n",
    "\n",
    "Also, you can use Watson Studio to run these notebooks faster with bigger datasets. Watson Studio is IBM's leading cloud solution for data scientists, built by data scientists. With Jupyter notebooks, RStudio, Apache Spark and popular libraries pre-packaged in the cloud, Watson Studio enables data scientists to collaborate on their projects without having to install anything. Join the fast-growing community of Watson Studio users today with a free account at <a href=\"https://cocl.us/ML0101EN_DSX\">Watson Studio</a>\n",
    "\n",
    "<h3>Thanks for completing this lesson!</h3>\n",
    "\n",
    "<h4>Author:  <a href=\"https://ca.linkedin.com/in/saeedaghabozorgi\">Saeed Aghabozorgi</a></h4>\n",
    "<p><a href=\"https://ca.linkedin.com/in/saeedaghabozorgi\">Saeed Aghabozorgi</a>, PhD is a Data Scientist in IBM with a track record of developing enterprise level applications that substantially increases clients’ ability to turn data into actionable knowledge. He is a researcher in data mining field and expert in developing advanced analytic methods like machine learning and statistical modelling on large datasets.</p>\n",
    "\n",
    "<hr>\n",
    "\n",
    "<p>Copyright &copy; 2018 <a href=\"https://cocl.us/DX0108EN_CC\">Cognitive Class</a>. This notebook and its source code are released under the terms of the <a href=\"https://bigdatauniversity.com/mit-license/\">MIT License</a>.</p>"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python",
   "language": "python",
   "name": "conda-env-python-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.7"
  },
  "widgets": {
   "state": {},
   "version": "1.1.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
